package com.sunlake.spring.main.model.auth.service.impl;
import com.sunlake.spring.main.common.enums.role.RoleEnum;
import com.sunlake.spring.main.common.enums.status.StatusEnum;
import com.sunlake.spring.main.common.response.R;
import com.sunlake.spring.main.common.utils.PasswordEncoderUtil;
import com.sunlake.spring.main.model.auth.dto.*;
import com.sunlake.spring.main.model.auth.mapper.PermissionMapper;
import com.sunlake.spring.main.model.auth.mapper.UsersMapper;
import com.sunlake.spring.main.model.auth.po.UsersPO;
import com.sunlake.spring.main.model.auth.po.VerificationPO;
import com.sunlake.spring.main.model.auth.po.VerifyPO;
import com.sunlake.spring.main.model.auth.service.AuthService;
import com.sunlake.spring.main.model.auth.vo.LoginVO;
import com.sunlake.spring.main.common.utils.JwtTokenUtil;
import com.sunlake.spring.main.common.utils.MailUtil;
import com.sunlake.spring.main.common.utils.RedisUtils;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

// added import
import com.sunlake.spring.main.config.JwtConfig;
import com.sunlake.spring.main.common.utils.RsaCryptoService;

@Service
public class AuthServiceImpl implements AuthService {
    public final Integer TIME_OUT = 5;
    @Autowired
    private MailUtil mailUtil;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private UsersMapper usersMapper;
    @Autowired
    private PermissionMapper permissionMapper;
    // inject JwtConfig instead of using new JwtConfig()
    @Autowired
    private JwtConfig jwtConfig;
    @Autowired
    private RsaCryptoService rsaCryptoService;
    @Override
    public R login(LoginDTO loginDTO) {
        UsersPO user = usersMapper.selectByEmail(loginDTO.getEmail());
        // 检查用户是否存在
        if (user == null) {
            return R.error(404, "用户不存在");
        }
        // 解密前端传来的（可能是RSA加密的）密码
        String decrypted = rsaCryptoService.decryptBase64(loginDTO.getPassword());
        if (decrypted == null) {
            return R.error(400, "密码解析失败");
        }
        // 检查密码是否匹配
        if (!PasswordEncoderUtil.matchesPassword(decrypted, user.getPassword())) {
            return R.error(401, "密码错误");
        }
        // 确保用户角色正确设置
        if (user.getRole() == null) {
            user.setRole(RoleEnum.USER);
        }
        String token = jwtTokenUtil.generateToken(user);
        String refreshToken = jwtTokenUtil.generateRefreshToken(Long.valueOf(user.getId()), user.getUsername());

        // Set-Cookie: refresh token
        ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attrs != null) {
            HttpServletResponse response = attrs.getResponse();
            if (response != null) {
                Cookie cookie = new Cookie("refresh_token", refreshToken);
                cookie.setHttpOnly(true);
                cookie.setPath("/");
                cookie.setMaxAge((int) (jwtConfig.getRefreshExpireTime()));
                response.addCookie(cookie);
            }
        }
        Map<String, Object> result = new HashMap<>();
        if (user.getRole() != null) {
            result.put("role", user.getRole().getCode());
        }
        return R.ok(200, "登录成功", result, token);
    }

    @Override
    public R VerificationCode(VerificationDTO verificationDTO) {
        VerificationPO verificationPO = new VerificationPO();
        verificationPO.setEmail(verificationDTO.getEmail());
        String code = String.format("%06d", new Random().nextInt(1000000));

        // 检查邮箱是否已存在验证码
        if (redisUtils.hasKey(verificationPO.getEmail())) {
            return R.error(400, "邮箱已发送验证码，请稍后重试");
        }

        // 存储验证码到Redis
        redisUtils.set(verificationPO.getEmail(), code, TIME_OUT, TimeUnit.MINUTES);

        // 生成并存储 verificationToken
        String verificationToken = UUID.randomUUID().toString();
        String tokenKey = "verificationToken:" + verificationPO.getEmail();
        redisUtils.set(tokenKey, verificationToken, TIME_OUT, TimeUnit.MINUTES);

        // 发送验证码邮件
//        boolean sendResult = mailUtil.sendVerificationCode(verificationPO.getEmail(), code);
        boolean sendResult = true;
        System.out.println("验证码：" + code);
        if (sendResult) {
            Map<String, Object> result = new HashMap<>();
            result.put("verificationToken", verificationToken);
            return R.ok(200, "验证码已发送", result);
        } else {
            return R.error(500, "验证码发送失败，请稍后重试");
        }
    }

    @Override
    public R validateVerificationCode(VerifyDTO verifyDTO) {
        VerifyPO verifyPO = new VerifyPO();
        verifyPO.setEmail(verifyDTO.getEmail());
        verifyPO.setCode(verifyDTO.getCode());
        verifyPO.setPurpose(verifyDTO.getPurpose());
        verifyPO.setVerificationToken(verifyDTO.getVerificationToken());
        // 验证 verificationToken
        String tokenKey = "verificationToken:" + verifyPO.getEmail();
        String storedToken = (String) redisUtils.get(tokenKey);
        if (storedToken == null || !storedToken.equals(verifyPO.getVerificationToken())) {
            return R.error(400, "无效或过期的 verificationToken");
        }
        // 验证验证码
        String code = (String) redisUtils.get(verifyPO.getEmail());
        if (code == null) {
            return R.error(400, "验证码过期，请重新发送");
        } else if (!code.equals(verifyPO.getCode())) {
            return R.error(400, "验证码错误");
        } else {
            return R.ok(200, "验证码验证成功");
        }
    }

    @Override
    public R register(RegisterDTO registerDTO) {
        // 检查用户名是否已存在
        UsersPO existingUserByUsername = usersMapper.selectByUsername(registerDTO.getUsername());
        if (existingUserByUsername != null) {
            return R.error(400, "用户名已存在，请选择其他用户名");
        }
        
        // 检查邮箱是否已存在
        UsersPO existingUserByEmail = usersMapper.selectByEmail(registerDTO.getEmail());
        if (existingUserByEmail != null) {
            return R.error(400, "邮箱已被注册，请使用其他邮箱");
        }
        
        UsersPO usersPO = new UsersPO();
        usersPO.setUsername(registerDTO.getUsername());
        usersPO.setEmail(registerDTO.getEmail());
//        usersPO.setPassword(registerDTO.getPassword());
        usersPO.setPassword(PasswordEncoderUtil.encodePassword(registerDTO.getPassword()));
        usersPO.setRole(RoleEnum.USER);
        LocalDateTime now = LocalDateTime.now();
        usersPO.setCreatedAt(now);
        usersPO.setStatus(StatusEnum.ACTIVE);
        int result = usersMapper.insertSelective(usersPO);
        if (result > 0) {
            String accessToken = jwtTokenUtil.generateToken(usersPO);
            Long id = Long.valueOf(usersPO.getId());
            String refreshToken = jwtTokenUtil.generateRefreshToken(id, usersPO.getUsername());

            // Set HttpOnly cookie for refresh token
            ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attrs != null) {
                HttpServletResponse response = attrs.getResponse();
                if (response != null) {
                    Cookie cookie = new Cookie("refresh_token", refreshToken);
                    cookie.setHttpOnly(true);
                    cookie.setPath("/");
                    // cookie.setSecure(true); // enable on HTTPS
                    cookie.setMaxAge((int) (jwtConfig.getRefreshExpireTime()));
                    response.addCookie(cookie);
                }
            }

            // Do not return refresh token in body
            Map<String, Object> data = new HashMap<>();
            data.put("role", usersPO.getRole().getCode());
            data.put("userId", usersPO.getId());
            return R.ok(200, "注册成功", data, accessToken);
        } else {
            return R.error(500, "注册失败，请稍后重试");
        }
    }

    @Override
    public R fetchUserInfo(FetchDTO fetchDTO) {
        String token = fetchDTO.getToken().replaceAll("^|$", "");
        if (token.isEmpty()) {
            return R.error(400, "token不能为空");
        }
        Claims claims = jwtTokenUtil.getClaimsFromToken(token);
        if (claims == null) {
            return R.error(400, "token无效");
        }
        Long userId = jwtTokenUtil.getUserIdFromToken(token);
        UsersPO user = usersMapper.selectByPrimaryKey(userId);
        if (user == null) {
            return R.error(404, "用户不存在");
        }

        String accessToken = jwtTokenUtil.generateToken(user);
        String refreshToken = jwtTokenUtil.generateRefreshToken(userId, user.getUsername());

        // refresh token cookie on fetch
        ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attrs != null) {
            HttpServletResponse response = attrs.getResponse();
            if (response != null) {
                Cookie cookie = new Cookie("refresh_token", refreshToken);
                cookie.setHttpOnly(true);
                cookie.setPath("/");
                // cookie.setSecure(true);
                cookie.setMaxAge((int) (jwtConfig.getRefreshExpireTime()));
                response.addCookie(cookie);
            }
            String role = user.getRole().getCode();
            // do not expose refreshToken in body; pass null for compatibility
            LoginVO loginVO = new LoginVO(user.getId(), user.getUsername(), user.getEmail(), null, role);

            return R.ok(200, "用户信息获取成功", loginVO, accessToken);
        }
        return R.error(500, "用户信息获取失败，请稍后重试");
    }

    @Override
    public R updateUserInfo(UpdateDTO updateDTO) {
        UsersPO usersPO = new UsersPO();
        usersPO.setId(updateDTO.getUserId());
        usersPO.setUsername(updateDTO.getUsername());
        usersPO.setEmail(updateDTO.getEmail());
        usersPO.setRole(RoleEnum.valueOf(updateDTO.getRole()));
        usersPO.setStatus(StatusEnum.valueOf(updateDTO.getStatus()));
        PermissionDTO permissionDTO = new PermissionDTO();
        permissionDTO.setUserId(Long.valueOf(updateDTO.getUserId()));
        permissionDTO.setAllowComment(updateDTO.isAllowComment() ? "true" : "false");
        permissionDTO.setAllowPost(updateDTO.isAllowPost() ? "true" : "false");
        int isUpdated = usersMapper.updateByPrimaryKeySelective(usersPO);
        int isPermissionUpdated = permissionMapper.updateByPrimaryKey(permissionDTO);

        if (isUpdated > 0 && isPermissionUpdated > 0) {
            return R.ok(200, "用户信息更新成功");
        } else {
            return R.error(500, "用户信息更新失败，请稍后重试");
        }
    }


    @Override
    public R resetPassword(ResetPasswordDTO resetPasswordDTO) {
        String email = resetPasswordDTO.getEmail();
        String newPassword = resetPasswordDTO.getNewPassword();
        String verificationCode = resetPasswordDTO.getVerificationCode();

        String code = (String) redisUtils.get(email);
        if (code == null) {
            return R.error(400, "验证码过期，请重新发送");
        } else if (!code.equals(verificationCode)) {
            return R.error(400, "验证码错误");
        }

        // 更新用户密码
        UsersPO user = usersMapper.selectByEmail(email);
        if (user == null) {
            return R.error(404, "用户不存在");
        }
        user.setPassword(PasswordEncoderUtil.encodePassword(newPassword));
        usersMapper.updateByPrimaryKeySelective(user);

        return R.ok(200, "密码重置成功");
    }


}